﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using WBoy.WeixinCore.Cache;
using WBoy.WeixinCore.Exceptions;
using WBoy.WeixinCore.Models;

namespace WBoy.WeixinCore
{
    public class AuthHelper
    {
        private readonly string _appId;
        private readonly string _appSecret;
        private readonly ICache _cache;
        private readonly string _token;

        /// <summary>
        /// 获取微信授权凭证
        /// 这个就是自己要保管好的私有Key了（切记只能放在自己的后台代码里，不能放在任何可能被看到源代码的客户端程序中）
        /// 每次自己Post数据给API的时候都要用这个key来对所有字段进行签名，生成的签名会放在Sign这个字段，API收到Post数据的时候也会用同样的签名算法对Post过来的数据进行签名和验证
        /// 收到API的返回的时候也要用这个key来对返回的数据算下签名，跟API的Sign数据进行比较，如果值不一致，有可能数据被第三方给篡改
        /// 微信分配的公众号ID（开通公众号之后可以获取到）
        /// </summary>
        /// <param name="appId">appId</param>
        /// <param name="appSecret">appSecret</param>
        public AuthHelper(string appId, string appSecret)
        {
            _appId = appId;
            _appSecret = appSecret;
            _cache = new MemoryCacheService();
        }
        /// <summary>
        /// 获取微信授权凭证
        /// 这个就是自己要保管好的私有Key了（切记只能放在自己的后台代码里，不能放在任何可能被看到源代码的客户端程序中）
        /// 每次自己Post数据给API的时候都要用这个key来对所有字段进行签名，生成的签名会放在Sign这个字段，API收到Post数据的时候也会用同样的签名算法对Post过来的数据进行签名和验证
        /// 收到API的返回的时候也要用这个key来对返回的数据算下签名，跟API的Sign数据进行比较，如果值不一致，有可能数据被第三方给篡改
        /// 微信分配的公众号ID（开通公众号之后可以获取到）
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="appSecret"></param>
        /// <param name="token"></param>
        public AuthHelper(string appId, string appSecret, string token)
        {
            _appId = appId;
            _appSecret = appSecret;
            _cache = new MemoryCacheService();
            _token = token;
        }
        /// <summary>
        /// 校验签名是否正确
        /// </summary>
        /// <param name="signature">签名</param>
        /// <param name="timestamp">timestamp</param>
        /// <param name="nonce">nonce</param>
        /// <param name="token">token</param>
        /// <returns></returns>
        public bool CheckSignature(string signature, string timestamp, string nonce, string token)
        {
            string[] arrTmp = { token, timestamp, nonce };

            Array.Sort(arrTmp);
            string tmpStr = string.Join("", arrTmp);

            tmpStr = tmpStr.SHA1().ToLower();

            if (tmpStr == signature)
            {
                return true;
            }

            return false;

        }
        public bool CheckSignature(string signature, string timestamp, string nonce)
        {
            string[] arrTmp = { _token, timestamp, nonce };

            Array.Sort(arrTmp);
            string tmpStr = string.Join("", arrTmp);

            tmpStr = tmpStr.SHA1().ToLower();

            if (tmpStr == signature)
            {
                return true;
            }

            return false;

        }
        /// <summary>
        /// 获取jsSDK签名
        /// </summary>
        /// <param name="noncestr">生成签名的随机串</param>
        /// <param name="timestamp">当前时间戳</param>
        /// <param name="pageurl">页面地址</param>
        /// <returns></returns>
        public JsSignature GetSignature(string noncestr, string timestamp, string pageurl)
        {
            var ticket = GetJsapiTicket();
            var tmpStr = $"jsapi_ticket={ticket}&noncestr={noncestr}&timestamp={timestamp}&url={pageurl}";
            var signature = tmpStr.SHA1().ToLower();
            return new JsSignature() { Jsapi_ticket = ticket, Signature = signature };
        }
        /// <summary>
        /// 获取jsSDK签名
        /// </summary>
        /// <param name="ticket">ticket</param>
        /// <param name="noncestr">生成签名的随机串</param>
        /// <param name="timestamp">当前时间戳</param>
        /// <param name="pageurl">页面地址</param>
        /// <returns></returns>
        public JsSignature GetSignature(string ticket, string noncestr, string timestamp, string pageurl)
        {
            var tmpStr = $"jsapi_ticket={ticket}&noncestr={noncestr}&timestamp={timestamp}&url={pageurl}";
            var signature = tmpStr.SHA1().ToLower();
            return new JsSignature() { Jsapi_ticket = ticket, Signature = signature };
        }
        /// <summary>
        /// 获取微信认证ticket
        /// </summary>
        /// <returns></returns>
        private string GetJsapiTicket()
        {
            var accessToken = GetAccessToken();
            return GetJsapi_Ticket(accessToken);
        }
        /// <summary>
        /// 获取微信认证ticket
        /// </summary>
        /// <param name="accessToken"></param>
        /// <returns></returns>
        private string GetJsapi_Ticket(string accessToken)
        {
            var jsapiTicket = _cache.Get<JsApiTicket>("WXjsapi_ticket");
            if (jsapiTicket != null)
            {
                return jsapiTicket.Ticket;
            }
            var url = $"https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={accessToken}&type=jsapi";

            var request = new WebRequestHelper();
            try
            {
                string result = request.RequestGetDataUrl(url);
                jsapiTicket = JsonConvert.DeserializeObject<JsApiTicket>(result);
                if (!string.IsNullOrEmpty(jsapiTicket?.Ticket))
                {
                    //微信 获取的有效期7200秒(2小时)  我们这里缓存6600秒
                    _cache.Set("WXjsapi_ticket", jsapiTicket, 6600);
                    return jsapiTicket.Ticket;
                }
                var errorMsg = JsonConvert.DeserializeObject<ErrorMsg>(result);
                
                throw new WeixinException(errorMsg.Errcode,errorMsg.Errmsg);
            }
            catch (Exception ex)
            {
                throw new WeixinException(-1, ex.Message);
            }
        }

        /// <summary>
        /// 获取微信认证access_token
        /// </summary>
        /// <returns></returns>
        public string GetAccessToken()
        {
            var accessToken = _cache.Get<AccessToken>("WXAccess_token");
            if (accessToken != null)
            {
                return accessToken.Access_token;
            }
            var url =$"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={_appId}&secret={_appSecret}";
            var request = new WebRequestHelper();
            try
            {
                var result = request.RequestGetDataUrl(url);
                accessToken = JsonConvert.DeserializeObject<AccessToken>(result);
                if (!string.IsNullOrEmpty(accessToken?.Access_token))
                {
                    //微信 获取的有效期7200秒(2小时) 我们这里缓存6600秒
                    _cache.Set("WXAccess_token", accessToken, 6600);
                    return accessToken.Access_token;
                }
                var errorMsg = JsonConvert.DeserializeObject<ErrorMsg>(result);
                throw new WeixinException(errorMsg.Errcode, errorMsg.Errmsg);
            }
            catch (Exception ex)
            {
                throw new WeixinException(-1, ex.Message);
            }

        }
        /// <summary>
        /// 通过Code 获取微信网页认证access_token 返回OpenId
        /// </summary>
        /// <returns></returns>
        public WebAccessToken GetWebAccessToken(string code)
        {
            //var accessToken = _cache.Get<WebAccessToken>($"WXWebAccess_token_{code}");
            //if (accessToken != null)
            //{
            //    return accessToken;
            //}
            var url = $"https://api.weixin.qq.com/sns/oauth2/access_token?appid={_appId}&secret={_appSecret}&code={code}&grant_type=authorization_code";
            var request = new WebRequestHelper();
            try
            {
                var result = request.RequestGetDataUrl(url);
                //LoggerFactory.CreateLog().LogError("WeiXin GetAccessToken result:{0},", result);
                var accessToken = JsonConvert.DeserializeObject<WebAccessToken>(result);
                if (!string.IsNullOrEmpty(accessToken?.Access_token))
                {
                    ////获取的有效期7200秒(2小时) 我们这里缓存6600秒
                    //_cache.Set($"WXWebAccess_token_{code}", accessToken, 6600);
                    return accessToken;
                }
                var errorMsg = JsonConvert.DeserializeObject<ErrorMsg>(result);
                throw new WeixinException(errorMsg.Errcode, errorMsg.Errmsg);
            }
            catch (Exception ex)
            {
                throw new WeixinException(-1, ex.Message);
            }

        }
        /// <summary>
        /// 刷新 access_token 由于access_token拥有较短的有效期，当access_token超时后，可以使用refresh_token进行刷新，refresh_token有效期为30天，当refresh_token失效之后，需要用户重新授权。
        /// </summary>
        /// <param name="refresh_token"></param>
        /// <returns></returns>
        public WebAccessToken RefreshWebAccessToken(string refresh_token)
        {
            var url = $"https://api.weixin.qq.com/sns/oauth2/refresh_token?appid={_appId}&grant_type=refresh_token&refresh_token={refresh_token}";
            var request = new WebRequestHelper();
            try
            {
                var result = request.RequestGetDataUrl(url);
                //LoggerFactory.CreateLog().LogError("WeiXin refresh_token result:{0},", result);
                var accessToken = JsonConvert.DeserializeObject<WebAccessToken>(result);
                if (!string.IsNullOrEmpty(accessToken?.Access_token))
                {
                    return accessToken;
                }
                var errorMsg = JsonConvert.DeserializeObject<ErrorMsg>(result);
                throw new WeixinException(errorMsg.Errcode, errorMsg.Errmsg);
            }
            catch (Exception ex)
            {
                throw new WeixinException(-1, ex.Message);
            }

        }
        /// <summary>
        /// 检验授权凭证（access_token）是否有效
        /// </summary>
        /// <param name="accessToken"></param>
        /// <param name="openId"></param>
        /// <returns></returns>
        public bool ValidateWebAccessToken(string accessToken,string openId)
        {
            var url = $"https://api.weixin.qq.com/sns/auth?access_token=ACCESS_TOKEN&openid=OPENID ";
            var request = new WebRequestHelper();
            try
            {
                var result = request.RequestGetDataUrl(url);
                var errorMsg = JsonConvert.DeserializeObject<ErrorMsg>(result);
                if (errorMsg.Errcode == 0)
                    return true;
                //LoggerFactory.CreateLog().LogError("WeiXin refresh_token failed, Errcode:{0},Errmsg:{1}", errorMsg.Errcode, errorMsg.Errmsg);
                //throw new NeedToShowFrontException($"Errcode:{errorMsg.Errcode},Errmsg:{errorMsg.Errmsg}");
                return false;
            }
            catch (Exception ex)
            {
                throw new WeixinException(-1, ex.Message);
            }

        }
        /// <summary>
        /// 获取微信用户信息（web应用获取）
        /// </summary>
        /// <param name="accessToken"></param>
        /// <param name="openId"></param>
        /// <returns></returns>
        public WeiXinUserInfo GetUserInfo(string accessToken, string openId)
        {
            var url = $" https://api.weixin.qq.com/sns/userinfo?access_token={accessToken}&openid={openId}&lang=zh_CN";
            var request = new WebRequestHelper();
            var result = request.RequestGetDataUrl(url);
            //LoggerFactory.CreateLog().LogError("WeiXin GetUserInfo result:{0}", result);
            var userInfo = JsonConvert.DeserializeObject<WeiXinUserInfo>(result);
            if (!string.IsNullOrEmpty(userInfo?.Unionid))
            {
                return userInfo;
            }
            var errorMsg = JsonConvert.DeserializeObject<ErrorMsg>(result);
            throw new WeixinException(errorMsg.Errcode, errorMsg.Errmsg);
        }
        /// <summary>
        /// 获取微信用户信息 （需要关注改公众号）
        /// </summary>
        /// <param name="openId"></param>
        /// <returns></returns>
        public WeiXinUserInfo GetUserInfo(string openId)
        {
            var accessToken = GetAccessToken();
            var url = $"https://api.weixin.qq.com/cgi-bin/user/info?access_token={accessToken}&openid={openId}&lang=zh_CN ";
            var request = new WebRequestHelper();
            var result = request.RequestGetDataUrl(url);
            //LoggerFactory.CreateLog().LogError("WeiXin GetUserInfo result:{0}", result);
            var userInfo = JsonConvert.DeserializeObject<WeiXinUserInfo>(result);
            if (!string.IsNullOrEmpty(userInfo?.Unionid))
            {
                return userInfo;
            }
            var errorMsg = JsonConvert.DeserializeObject<ErrorMsg>(result);
            throw new WeixinException(errorMsg.Errcode, errorMsg.Errmsg);
        }
       
        
       

    }
}
